02. 列表、字典和元组

本章概览:Python三大复合数据类型

在金融数据分析中,我们经常需要处理成组的相关数据

Python提供了三种核心复合数据类型:

类型 特点 典型应用
列表 (List) 可变、有序 股价时间序列
字典 (Dictionary) 键值对、快速查找 股票信息存储
元组 (Tuple) 不可变、安全 固定配置参数

数据结构的性能特征

从计算机科学角度看,三种数据类型代表了不同的抽象层次:

  • 列表:动态数组,O(1)随机访问,O(n)插入/删除
  • 字典:哈希表,平均O(1)查找、插入和删除
  • 元组:不可变序列,可作为字典键
三种数据结构性能对比 列表、字典、元组的性能特征对比图 列表 (List) ✅ 有序、可变 ✅ O(1) 随机访问 ⚠️ O(n) 查找 适用:时间序列 0 1 2 3 字典 (Dict) ✅ 键值对 ✅ O(1) 查找 ⚠️ 键须不可变 适用:股票信息 key value 元组 (Tuple) ✅ 有序、不可变 ✅ 可做字典键 ✅ 线程安全 适用:固定配置 0 1 2 🔒

第一部分:列表 (List)

列表是Python中最常用的数据结构之一:

  • 可变的 (Mutable):可以增删改元素
  • 有序的 (Ordered):元素按插入顺序排列
  • 异构的:可以包含不同类型的元素

在金融应用中,列表常用于存储:

  • 时间序列数据(日期、价格序列)
  • 投资组合成分(股票代码列表)
  • 交易记录集合

⭐ 列表的创建——混合类型列表

Listing 1
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#列表应用
x=['finance','risk management','金融风险管理',8.88]
print(x)  # 输出混合类型列表的内容(含字符串、数值等多种数据类型)
['finance', 'risk management', '金融风险管理', 8.88]

列表的异构性与内存模型

列表可以包含不同类型的元素(这是Python列表的独特优势):

  • 字符串 'finance'、数值 8.88 可以共存
  • 列表存储的是对象的引用而非对象本身

关键时间复杂度

操作 复杂度 说明
x[i] 索引访问 O(1) 直接定位
x[a:b] 切片 O(k) k为切片长度
len(x) O(1) 内置存储长度
x.append() 均摊O(1) 动态数组扩容

实战:用列表管理投资组合

Listing 2
# 创建初始投资组合(存储A股股票代码)
portfolio = ['600519.SH', '000858.SZ', '600036.SH', '000002.SZ']
# 6位数字.SH(上海)或.SZ(深圳)

# 添加新股票(末尾追加,均摊O(1))
portfolio.append('601318.SH')  # 中国平安

# 移除股票(需遍历查找,O(n))
portfolio.remove('000002.SZ')  # 万科A

# 输出当前持仓
print(f'当前持仓股票数量: {len(portfolio)}')
for i, stock in enumerate(portfolio, start=1):
    print(f'  {i}. {stock}')
当前持仓股票数量: 4
  1. 600519.SH
  2. 000858.SZ
  3. 600036.SH
  4. 601318.SH

列表常用方法速查

方法 功能 示例
append(x) 末尾添加元素 lst.append('new')
remove(x) 删除第一个匹配 lst.remove('old')
insert(i,x) 指定位置插入 lst.insert(0,'first')
pop(i) 删除并返回元素 lst.pop(-1)
sort() 原地排序 lst.sort()
reverse() 原地反转 lst.reverse()
index(x) 查找元素位置 lst.index('target')

注意appendsortreverse 都是原地修改,返回 None

第二部分:字典 (Dictionary)

字典是Python中最重要的数据结构之一:

  • 可变的:可以增删改键值对
  • Python 3.7+ 保持插入顺序
  • 基于哈希表实现,查找速度极快

字典的核心特点是键值对 (Key-Value Pair) 结构:

  • 键 (Key):必须是不可变类型(str, int, float, tuple)
  • 值 (Value):可以是任意类型

⭐ 字典的创建——沪深300指数信息

Listing 3
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#字典应用
dict1={'指数名称':'沪深300',
      '证券代码':'000300',  # 沪深300指数的证券代码
      '交易日期':'2022-09-14',  # 交易日期
      '涨跌幅':0.42  # 当日涨跌幅(百分比)
    }  # 创建沪深300指数信息字典
print(dict1)  # 输出沪深300指数信息字典
{'指数名称': '沪深300', '证券代码': '000300', '交易日期': '2022-09-14', '涨跌幅': 0.42}

字典底层原理:哈希表

字典底层使用哈希表 (Hash Table) 实现:

  1. 通过 hash(key) 计算哈希值
  2. 哈希值决定存储位置(桶)
  3. 哈希冲突通过开放寻址法解决

性能对比

操作 字典 列表
查找元素 O(1) O(n)
插入元素 O(1) O(n)
删除元素 O(1) O(n)
遍历全部 O(n) O(n)

键的要求:必须是不可变类型(int, str, tuple),不能是list或dict。

实战:字典存储股票信息

Listing 4
# 创建股票信息字典
stock_info = {
    'code': '600519.SH',
    'name': '贵州茅台',
    'price': 1850.00,
    'volume': 2500000
}

# 更新股价
stock_info['price'] = 1860.00

# 添加新字段(市盈率)
stock_info['pe_ratio'] = 45.5

# 检查字段是否存在
if 'market_cap' in stock_info:
    print(f'市值: {stock_info["market_cap"]}')
else:
    print('市值信息缺失')

# 批量更新
stock_info.update({'price': 1870.00, 'volume': 2600000})
print(stock_info)
市值信息缺失
{'code': '600519.SH', 'name': '贵州茅台', 'price': 1870.0, 'volume': 2600000, 'pe_ratio': 45.5}

字典常用方法速查

方法 功能 示例
d[key] 获取值(不存在报错) d['name']
d.get(key, default) 安全获取值 d.get('name', '未知')
d[key] = val 设置/更新值 d['price'] = 100
d.update(other) 批量更新 d.update({...})
key in d 检查键是否存在 'name' in d
d.keys() 获取所有键 返回视图对象
d.values() 获取所有值 返回视图对象
d.items() 获取所有键值对 返回视图对象

字典视图对象:动态反映变化

keys()values()items() 返回的是视图对象

Listing 5
# 两个字典
dict_a = {'a': 1, 'b': 2, 'c': 3}
dict_b = {'b': 2, 'c': 3, 'd': 4}

# 键的交集(两个字典共有的键)
common_keys = dict_a.keys() & dict_b.keys()
print(f'共有键: {common_keys}')  # {'b', 'c'}

# 键的差集(A有B没有的键)
unique_keys = dict_a.keys() - dict_b.keys()
print(f'A独有键: {unique_keys}')  # {'a'}
共有键: {'c', 'b'}
A独有键: {'a'}

视图对象支持集合运算:&(交集)、|(并集)、-(差集)

第三部分:元组 (Tuple)

元组是不可变的 (Immutable) 有序序列

不可变性带来的优势:

  • 线程安全:多线程环境下无需加锁
  • 可哈希:可以作为字典键或集合元素
  • 性能优化:Python可以进行内存优化
  • 数据完整性:防止意外修改

⭐ 元组的创建与切片操作

Listing 6
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#元组应用
tup=('finance','风险管理',2022,88.88)
print(tup[1:3])  # 输出元组切片(索引1到2的元素:'风险管理'和2022)
('风险管理', 2022)

切片规则 tup[start:end]

  • 包含 start 索引,不包含 end 索引
  • tup[1:3] → 索引1和索引2的元素

元组的高级用法:命名元组

标准元组只能通过索引访问,代码可读性差。命名元组解决了这个问题:

Listing 7
from collections import namedtuple

# 定义命名元组类型
Stock = namedtuple('Stock', ['code', 'name', 'price', 'volume'])

# 创建实例
stock = Stock('600519.SH', '贵州茅台', 1850.00, 2500000)

# 通过字段名访问(更直观)
print(f'股票名称: {stock.name}')
print(f'股票价格: {stock.price}')

# 仍然支持索引访问
print(f'股票代码: {stock[0]}')
股票名称: 贵州茅台
股票价格: 1850.0
股票代码: 600519.SH

数据类型选择指南

根据使用场景选择合适的数据类型:

场景 推荐类型 理由
时间序列数据 列表 有序、可动态增删
键值对数据 字典 O(1)快速查找
固定配置参数 元组 不可变、安全
去重数据 集合 自动去重
矩阵运算 NumPy数组 高性能数值计算

选择原则

  • 需要修改?→ 列表或字典
  • 需要快速查找?→ 字典
  • 数据不应被修改?→ 元组

性能实测:列表 vs 字典查找

Listing 8
import time

n = 1000000  # 100万元素
test_list = list(range(n))
test_dict = {i: f'value_{i}' for i in range(n)}

# 列表查找(O(n) - 需要逐个比较)
start = time.time()
result = 999999 in test_list
list_time = time.time() - start

# 字典查找(O(1) - 哈希直接定位)
start = time.time()
result = 999999 in test_dict
dict_time = time.time() - start

print(f'列表查找时间: {list_time:.6f}秒')
print(f'字典查找时间: {dict_time:.6f}秒')
if dict_time > 0:
    print(f'性能提升: {list_time / dict_time:.1f}倍')
列表查找时间: 0.007035秒
字典查找时间: 0.000000秒

深拷贝与浅拷贝:避免数据污染

浅拷贝与深拷贝对比 展示浅拷贝共享内层引用、深拷贝完全独立的区别 浅拷贝 vs 深拷贝 浅拷贝 (Shallow Copy) 原始列表 浅拷贝列表 共享内层对象⚠️ 修改原始 → 拷贝也变! 深拷贝 (Deep Copy) 原始列表 深拷贝列表 内层对象A 内层对象B 完全独立 ✅ 互不影响

拷贝机制代码演示

Listing 9
import copy

# 嵌套列表(模拟投资组合持仓)
portfolio = [
    ['600519.SH', 100, 1850.00],
    ['000858.SZ', 200, 85.50]
]

# 浅拷贝:内层仍然共享引用
portfolio_shallow = portfolio.copy()

# 深拷贝:完全独立的副本
portfolio_deep = copy.deepcopy(portfolio)

# 修改原始数据
portfolio[0][2] = 1900.00

# 浅拷贝受影响(共享内层引用)
print(f'浅拷贝: {portfolio_shallow[0][2]}')  # 1900.00

# 深拷贝不受影响(完全独立)
print(f'深拷贝: {portfolio_deep[0][2]}')  # 1850.00
浅拷贝: 1900.0
深拷贝: 1850.0

拷贝最佳实践

场景 方法 说明
简单列表(不含嵌套) list.copy()[:] 浅拷贝即可
嵌套结构 copy.deepcopy() 必须深拷贝
简单字典 dict.copy() 浅拷贝
嵌套字典 copy.deepcopy() 必须深拷贝

记住:处理金融数据时,数据安全性至关重要。当数据结构包含嵌套时,始终使用深拷贝

本章总结

三大数据类型核心特征

  • 列表:可变有序序列 → [] 创建
    • 适合:动态数据集合、时间序列
  • 字典:键值对映射 → {} 创建
    • 适合:结构化数据、快速查找
  • 元组:不可变有序序列 → () 创建
    • 适合:固定配置、数据完整性保护

关键要点

  • 查找操作多时选字典(O(1))
  • 数据不应修改时选元组
  • 嵌套结构拷贝用 copy.deepcopy()